#include "GOD.h"
#include "SGKAgent.h"
#include "Action.h"

#define NUM_OBJECTS 35

God::God()
	{
		world_conditions = new Condition[NONE]; // length of conditionID array.  WOOOOO.  now we can say world_conditions[GOTO] and get the right one.
		
		for (unsigned int i = 0; i < NONE; ++i) // I know this may seem a little confusing, but NONE is at least six in most for loops contained within God's constructor.
		{
			//value val;
			world_conditions[i] = Condition((conditionID)i, value(false));
		}

		for (unsigned int i = 0; i < NUM_OBJECTS; ++i)
		{
			Object bob;
			m_objects.push_back(bob);

			m_objects.back().pos.x = (float)((rand() % 41) - 20);
			m_objects.back().pos.y = 0.f;
			m_objects.back().pos.z = (float)((rand() % 41) - 20);

			if ((rand() % 2) == 0) m_objects.back().id = AMMO;
			else				   m_objects.back().id = GUN;

			if (i == 0)
				m_objects.back().id = PLAYER;
		}

		time_mod = TIME_MOD;
	}

// returns a value representing what the current condition evaluates to (regarding a particular agent if there is one), in the form of code.
// For example, HASOBJ evaluates to the OBJECT ID of the object owned by the relevant agent.  If the agent does not have an object, 
// it returns the object NOTHING.  It is important to return the subject of the condition in the form of a Value.
value God::EvaluateCondition(SGKAgent * regarding, Condition & condition) // conditions may need to be stored as they pertain to various instances. // this needs to be returned as a val.
{

	value vTrue(true);
	value vFalse(false);
	conditionID enumeration = condition.ID;

		switch(enumeration)
		{
		case PLAYERHURT:
			return vFalse;
			break;
		case HASGUN:
			if (regarding->GetTehObject() && regarding->GetTehObject()->id == GUN) return vTrue;
			return vFalse;
			break;
		case GUNAIMED:
			{
			if (regarding->GetTehObject() && regarding->GetTehObject()->id == LOADEDGUN)
				return vTrue;
			else
				return vFalse;
			}
			break;
		case WANTSOBJ:
			if (regarding->GetTehObject()) return value(regarding->GetTehObject()->id); // agent WANTS object, objects owner is hopefully 0
			return value(NOTHING);
			break;
		case HASOBJ:
			if (regarding->GetTehObject()) return value(regarding->GetTehObject()->id); // agent OWNS object, WINDOWS 7 DOESNT LIKE TO TALK ABOUT DEREFERENCING NULL AND IT TAKES ME HOURS TO TRACK DOWN CASES OF IT GARHHDGHJFK. [apparently there's an option in the debug menu, </rage>]
			return value(NOTHING);
			break;
		case ATOBJ:
			return GetObjAtLoc(regarding->GetCenter());
			break;
		case CANGETOBJ:
			{
				// note: this is not functioning properly.  some agents try and acquire guns when they cannot.  TODO: fix
			int ind = findMeA((OBJID)condition.active.u_value);
			if (ind != -1 && m_objects[ind].id == condition.active.u_value)
			return value(m_objects[ind].id);
			else
				return value(NOTHING);
			}
			break;
		case CANTGETOBJ:
			{
				// ...
				int ind = findMeA((OBJID)condition.active.u_value);
				if (ind != -1 && m_objects[ind].id == condition.active.u_value)
					return value(NOTHING);
				else
					return value((OBJID)condition.active.u_value);
			}
			break;
		default:
			//wat?
			break;
		};

		return vFalse;
}

// returns true if given action is DOable given current world conditions, false otherwise.
bool God::EvaluateAction(SGKAgent * regarding, Action * act)
{

	bool ret = true;

	for (unsigned int i = 0; i < act->pre.size() && ret; ++i)
	{
		ret = act->pre[i].EvaluateValues(EvaluateCondition(regarding, act->pre[i])); // Todo: fix this shit.
	}

	return ret;
}


void God::DrawObjects(void)
{
	for (unsigned int i = 0; i < NUM_OBJECTS; ++i)
	{
		m_objects[i].draw();
	}
}

int God::findGun(void)
{
	for (unsigned int i = 0; i < NUM_OBJECTS; ++i)
	{
		if (m_objects[i].id == GUN && m_objects[i].m_pOwner == 0)
			return i;
	}

	return -1;
}

Object * God::GetObject(int obj_id)
{
	if (obj_id > -1)
	return &m_objects[obj_id];

	return NULL;
}

bool God::isObjAtLoc(vec3f pos, OBJID id)
{
	for (unsigned int i = 0; i < NUM_OBJECTS; ++i)
	{
		if (m_objects[i].id == id && fabs(vec3f(m_objects[i].pos - pos).magnitude()) < 0.01f) return true;
	}

	return false;
}


value God::GetObjAtLoc(vec3f pos)
{
	float closest = 5.f; // max distance
	int index = -1;

	for (unsigned int i = 0; i < NUM_OBJECTS; ++i)
	{
		float dist = fabs(vec3f(m_objects[i].pos - pos).magnitude());
		if (dist < closest){
			closest = dist;
			index = i;
		}
	}

	if (index >= 0)
	{
		return value(m_objects[index].id);
	}
	else
		return value(NOTHING);
}

int God::findMeA(OBJID id)
{
	for (unsigned int i = 0; i < NUM_OBJECTS; ++i)
	{
		if (m_objects[i].id == id && m_objects[i].m_pOwner == 0)
			return i;
	}

	return -1;
}
